---
title: "Quebec Election Misinformation Project"
author: "Mathieu Lavigne"
date: "2026-04-07"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## Set working directory and load packages

```{r}
# Set working directory
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))

# Load packages (remove # and run first line if pacman package not already installed)
# install.packages("pacman")
pacman::p_load(tidyverse, survey, xtable, cocor, scales)
```

## Create folders for tables and figures

```{r}
if (!dir.exists("Figures")) {
  dir.create("Figures")
  message("Created 'Figures' folder.")
} else {
  message("'Figures' folder already exists.")
}

if (!dir.exists("Tables")) {
  dir.create("Tables")
  message("Created 'Tables' folder.")
} else {
  message("'Tables' folder already exists.")
}
```

## Load and clean data 

```{r}
# Load data from the Quebec Election Misinformation Project
datqc <- read_csv("./qemp.csv") 
```

## Recode data

```{r}
# Trust in Canadian and Quebec elections
datqc <- datqc %>% 
  mutate(
    fraud_yes = case_when(
      influence_1_post %in% c(3,4) ~ 1,
      influence_1_post %in% c(1,2) ~ 0,
      !is.na(completed_post) & is.na(influence_1_post) ~ 0,
      TRUE ~ NA_real_
    ),
    trust_results = case_when(
      trust_accuracy_3_post %in% c(4,5) ~ 1,
      trust_accuracy_3_post %in% c(1,2,3) ~ 0,
      !is.na(completed_post) & is.na(trust_accuracy_3_post) ~ 0
    ),
    counted_accurat = case_when(
      trust_accuracy_2_post %in% c(4,5) ~ 1,
      trust_accuracy_2_post %in% c(1,2,3) ~ 0,
      !is.na(completed_post) & is.na(trust_accuracy_2_post) ~ 0
    ),
    EQ_fair = case_when(
      fair_election_post %in% c(1,2) ~ 1,
      fair_election_post %in% c(3,4) ~ 0,
      !is.na(completed_post) & is.na(fair_election_post) ~ 0 
    ),
    trudeau_legitimate = case_when(
      legitimate_winner_1_pre %in% c(1,2,5) ~ 0,
      legitimate_winner_1_pre %in% c(3,4) ~ 1,
      TRUE ~ NA_real_
    ))

# Perceived legitimacy of Joe Biden's victory
datqc <- datqc %>% 
  mutate(biden_legitimate = case_when(
    legitimate_winner_2_pre %in% c(1,2,5) ~ 0,
    legitimate_winner_2_pre %in% c(3,4) ~ 1,
    TRUE ~ NA_real_
  ))

# Demographics
datqc <- datqc %>% 
  mutate(age_cat3_pre = case_when(
    age_pre >= 18 & age_pre < 35 ~ 0,
    age_pre >= 35 & age_pre < 55 ~ 0.5,
    age_pre >= 55 ~ 1
  ),
  educ_cat3_pre = case_when(
    education_pre %in% c(1:6) ~ 0, 
    education_pre %in% c(7:8) ~ 0.5,
    education_pre %in% c(9:11) ~ 1, 
    TRUE ~ NA_real_
  )
  )

# Survey designs (pre- and post-election)
datqc_nona <- filter(datqc, !is.na(wt_pre))
design_qc <- svydesign(ids=~1, data=datqc_nona, weights = datqc_nona$wt_pre)

datqc_nona_post <- filter(datqc, !is.na(wt_post))
design_qc_post <- svydesign(ids=~1, data=datqc_nona_post, weights = datqc_nona_post$wt_post)
```

## Table A5: Sample characteristics

```{r}
print(xtable(
  data.frame(
    Demographic = c("Gender", "",
                    "Age", "", "",
                    "Education", "", "",
                    "Region", "", ""),
    Category = c("Female", "Male",
                 "18-34", "25-54", "55+",
                 "High school or less", "College/CEGEP", "University",
                 "Montreal RMR", "Quebec RMR", "Other regions"),
    `Unweighted Pre` = c(prop.table(table(datqc_nona[["gender_group_pre"]])),
                         prop.table(table(datqc_nona[["age_cat3_pre"]])),
                         prop.table(table(datqc_nona[["educ_cat3_pre"]])),
                         prop.table(table(datqc_nona[["region.1_pre"]]))
    ),
    `Weighted Pre` = c(as.data.frame(svymean(~factor(gender_group_pre), design_qc, na.rm = T))$mean,
                       as.data.frame(svymean(~factor(age_cat3_pre), design_qc, na.rm = T))$mean,
                       as.data.frame(svymean(~factor(educ_cat3_pre), design_qc, na.rm = T))$mean,
                       as.data.frame(svymean(~factor(region.1_pre), design_qc, na.rm = T))$mean),
    `Unweighted Post` = c(prop.table(table(datqc_nona_post[["gender_group_pre"]])),
                          prop.table(table(datqc_nona_post[["age_cat3_pre"]])),
                          prop.table(table(datqc_nona_post[["educ_cat3_pre"]])),
                          prop.table(table(datqc_nona_post[["region.1_pre"]]))),
    `Weighted Post` = c(as.data.frame(svymean(~factor(gender_group_pre), design_qc_post, na.rm = T))$mean,
                        as.data.frame(svymean(~factor(age_cat3_pre), design_qc_post, na.rm = T))$mean,
                        as.data.frame(svymean(~factor(educ_cat3_pre), design_qc_post, na.rm = T))$mean,
                        as.data.frame(svymean(~factor(region.1_pre), design_qc_post, na.rm = T))$mean))),
  type = "html", file="./Tables/Table_A5_sample_qemp.html")
```

## Figure C2: Belief that Joe Biden is the legitimate winner of the 2020 election by ideology self-placement

```{r}
# Calculate weighted mean by ideology
biden_ideol <- svyby(~biden_legitimate, ~ideol_1_pre, design_qc, svymean, na.rm = T) %>% 
  mutate(
    # Calculate confidence intervals
    lower = biden_legitimate-1.96*se,
    upper=biden_legitimate+1.96*se,
    # Create categorical measure of ideology (for colors)
    ideol3 = case_when(
      ideol_1_pre %in% c(0,1,2,3) ~ "Left",
      ideol_1_pre %in% c(4,5,6) ~ "Moderate", 
      ideol_1_pre %in% c(7,8,9,10) ~ "Right"),
  ) %>% 
  # Create figure
  ggplot(aes(x=ideol_1_pre, y=biden_legitimate, ymin=lower, ymax=upper, col=factor(ideol3), shape=factor(ideol3)))+
  geom_point(size=2.5)+
  geom_errorbar(width=0)+
  scale_x_continuous(breaks=0:10)+
  scale_y_continuous(breaks=c(0.5,0.6,0.7,0.8,0.9,1), labels=percent_format(accuracy=1))+
  scale_colour_manual(values=c("red3", "darkgrey", "blue3"))+
  scale_shape_manual(values=c(17,16,15))+
  labs(x="Left-right ideology (0-10)",
       y="Percentage who perceive Biden as the legitimate winner")+
  guides(col="none", shape="none")+
  theme_minimal()+
  theme(panel.grid.minor.x = element_blank(),
        axis.title=element_text(size=11.5),
        axis.text=element_text(size=10.5));biden_ideol

# Save figure
ggsave(biden_ideol, file="./Figures/Figure_C2_biden_ideol.png", bg="white", height=4.5, width=7)
```

## Figure C3: Trust in Canadian and Quebec elections based on perceptions that Biden is the legitimate winner

```{r}
# Calculate weighted percentage based on perceptions that Biden is the legitimate winner
fair <- svyby(~EQ_fair, ~biden_legitimate, design_qc_post, svymean, na.rm = T) %>% 
  mutate(Variable = "Quebec:\nFairly") %>% 
  rename(value=EQ_fair)
count_accurat <- svyby(~counted_accurat, ~biden_legitimate, design_qc_post, svymean, na.rm = T)%>% 
  mutate(Variable = "Quebec:\nVotes counted\naccurately") %>% 
  rename(value=counted_accurat)
trust_results <- svyby(~trust_results, ~biden_legitimate, design_qc_post, svymean, na.rm = T)%>% 
  mutate(Variable = "Quebec:\nTrust results") %>% 
  rename(value=trust_results)
fraud_yes <- svyby(~fraud_yes, ~biden_legitimate, design_qc_post, svymean, na.rm = T)%>% 
  mutate(Variable = "Quebec: Fraud\ninfluenced\noutcome") %>% 
  rename(value=fraud_yes)
trudeau_legitimate <- svyby(~trudeau_legitimate, ~biden_legitimate, design_qc, svymean, na.rm = T)%>%
  mutate(Variable = "Canada: Trudeau\nlegitimate\nwinner") %>% 
  rename(value=trudeau_legitimate)

# Merge output
trust_qc <- rbind(fair, count_accurat, trust_results, fraud_yes, trudeau_legitimate) %>% 
  mutate(
    # Calculate confidence intervals
    lower = value-1.96*se,
    upper = value+1.96*se,
    # Create factor variables for types of trust
    Variable = factor(Variable, 
                      levels=rev(c("Canada: Trudeau\nlegitimate\nwinner", 
                                   "Quebec:\nFairly", 
                                   "Quebec:\nVotes counted\naccurately", 
                                   "Quebec:\nTrust results", 
                                   "Quebec: Fraud\ninfluenced\noutcome")),
                      labels = rev(c("Believe that Justin Trudeau was the legitimate\nwinner of the 2021 election",
                                     "Believe that Elections Quebec ran the election fairly",
                                     "Have confidence that the election was administered\nfairly and the votes were counted accurately",
                                     "Trust the results of the 2022 Quebec election",
                                     "Believe that vote fraud influenced the outcome\nof the 2022 Quebec election"))))

# Create figure
plot_trust_qc <- ggplot(trust_qc, 
                        aes(x=Variable, y=value, ymin=lower, ymax=upper, 
                            col=factor(biden_legitimate),
                            shape=factor(biden_legitimate)))+
  geom_point(size=2.5)+
  geom_errorbar(width=0, size=1)+
  geom_text(aes(label = paste0(round(value*100), "%")),
            size=3, vjust=-1, col="black")+
  scale_y_continuous(limits=c(0,1), label=percent_format(accuracy=1))+
  scale_color_manual(values=c("red4", "green3"), labels = c("No/Unsure", "Yes"))+
  scale_shape_manual(values=c(17, 16), labels = c("No/Unsure", "Yes"))+
  labs(x="",
       y="Weighted percentage of respondents",
       col="Biden is the legitimate winner of the 2020 U.S. election",
       shape="Biden is the legitimate winner of the 2020 U.S. election")+
  coord_flip()+
  theme_minimal()+
  theme(legend.position = "top",
        strip.text=element_text(size=10),
        axis.title=element_text(size=11.5),
        axis.text=element_text(size=10.5))

# Save figure
ggsave(plot_trust_qc, file="./Figures/Figure_C3_trust_qc.png", bg="white", height=4.5, width=9)
```
